﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Common.Tool.FileTools
{
    public class S19Helper
    {
        /******************************************************************************
         * 该部分为S19文件和srec文件解析规则 
         * S0，位于文件的第一行，和其他行不同，地址部分没有使用，用0000置位，整行表示记录的开始
         * S1表示地址长度为两字节（4字符）的记录，包含类型、长度、地址、数据和校验和五个部分
         * S2表示地址长度为三字节（6字符）的记录，包含类型、长度、地址、数据和校验和五个部分
         * S3表示地址长度为四字节（8字符）的记录，包含类型、长度、地址、数据和校验和五个部分
         * S5表示文件中含有S1、S2、S3记录的个数，其后不接数据，包含S5的记录并不是每个文件必须的
         * S7表示地址长度为四字节（8字符）的记录，包含类型、长度、地址和校验和四个部分，此行表示程序的结束
         * S8表示地址长度为三字节（6字符）的记录，包含类型、长度、地址和校验和四个部分，此行表示程序的结束
         * S9表示地址长度为两字节（4字符）的记录，包含类型、长度、地址和校验和四个部分，此行表示程序的结束
         * 只有S1、S2、S3需要写入Flash中
         * ***************************************************************************/

        public static List<Byte> ParseS19(string path, ref UInt32 startAddr)
        {
            try
            {
                uint sumLen = 0;//记录的是字符的长度
                int lineNum = 0;
                string szLine = ""; //数据处理临时字符串
                string sTemp = "";
                int nowLineAddressLen = 0;
                int nowLineRecordLen = 0;
                uint nowLineAddr;
                //打开文件
                StreamReader HexReader = new StreamReader(path);
                List<Byte> BinData = new List<byte>();
                while (true)
                {
                    //读取一行数据
                    szLine = HexReader.ReadLine();
                    //读完所有行导出最后一个块
                    if (szLine == null)
                    {
                        //Log("总函数：" + lineNum.ToString() + "，总长度：" + sumLen.ToString());
                        sumLen = 0;
                        break;
                    }
                    lineNum++;

                    //判断第1字符是否是S
                    if (szLine.Substring(0, 1) != "S")
                    {
                        HexReader.Close();
                        throw new Exception("S19文件第1个字符不是S");
                    }

                    //获取类型
                    sTemp = szLine.Substring(0, 2);
                    //为S0或S5 S7-S9则略过
                    if (sTemp == "S0" || sTemp == "S5" || sTemp == "S7" || sTemp == "S8" | sTemp == "S9")
                    {
                        continue;
                    }

                    //获取当前行内数据的地址长度
                    nowLineRecordLen = Convert.ToInt32(szLine.Substring(2, 2), 16);
                    //Console.WriteLine("line=" + lineNum.ToString() + ",len=" + nowLineRecordLen.ToString());
                    if (nowLineRecordLen % 2 != 0)
                    {
                        //throw new Exception("S19文件第"+lineNum.ToString()+ "行数据长度不对");
                    }
                    if (szLine == "S3157001BCDC54FF06EFB70F12F78FFF83218F2200F0F7")
                    {
                        //BinData.Add(0x00);
                        //BinData.Add(0x00); 
                        //BinData.Add(0x00);
                        //BinData.Add(0x00);
                        //BinData.Add(0x00);
                        //BinData.Add(0x00);
                    }
                    //获取当前行内数据的地址
                    nowLineAddressLen = ParseAddressLen(sTemp);
                    nowLineAddr = Convert.ToUInt32(szLine.Substring(4, nowLineAddressLen), 16);
                    //首行地址当作文件起始地址
                    if (sumLen == 0)
                    {
                        startAddr = nowLineAddr;
                    }
                    //记录数据

                    int dataLen = nowLineRecordLen * 2 - nowLineAddressLen - 2;
                    sTemp = szLine.Substring(4 + nowLineAddressLen, dataLen);
                    for (int i = 0; i < dataLen; i += 2)
                    {
                        string valStr = sTemp.Substring(i, 2);
                        BinData.Add(Convert.ToByte(valStr, 16));
                        sumLen += 1;
                    }
                }
                HexReader.Close();
                return BinData;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        //返回地址长度
        private static int ParseAddressLen(string SecondFlag)
        {
            int AddressLen = 0;
            switch (SecondFlag)
            {
                case "S0":
                    AddressLen = 2 * 2;
                    break;
                case "S1":
                    AddressLen = 2 * 2;
                    break;
                case "S2":
                    AddressLen = 3 * 2;
                    break;
                case "S3":
                    AddressLen = 4 * 2;
                    break;
                case "S7":
                    AddressLen = 4 * 2;
                    break;
                case "S8":
                    AddressLen = 3 * 2;
                    break;
                case "S9":
                    AddressLen = 2 * 2;
                    break;
            }
            return AddressLen;
        }

    }
}
